#ifndef __PHY_H__
#define __PHY_H__



#include "qelib.h"

typedef enum {
    PHY_INTERFACE_MODE_MII,
    PHY_INTERFACE_MODE_GMII,
    PHY_INTERFACE_MODE_SGMII,
    PHY_INTERFACE_MODE_SGMII_2500,
    PHY_INTERFACE_MODE_QSGMII,
    PHY_INTERFACE_MODE_TBI,
    PHY_INTERFACE_MODE_RMII,
    PHY_INTERFACE_MODE_RGMII,
    PHY_INTERFACE_MODE_RGMII_ID,
    PHY_INTERFACE_MODE_RGMII_RXID,
    PHY_INTERFACE_MODE_RGMII_TXID,
    PHY_INTERFACE_MODE_RTBI,
    PHY_INTERFACE_MODE_XGMII,
    PHY_INTERFACE_MODE_XAUI,
    PHY_INTERFACE_MODE_RXAUI,
    PHY_INTERFACE_MODE_SFI,
    PHY_INTERFACE_MODE_INTERNAL,
    PHY_INTERFACE_MODE_NONE,
    PHY_INTERFACE_MODE_SIZEOF,
}phy_interface_mode;

#define PHY_FIXED_ID		0xa5a55a5a

#define PHY_MAX_ADDR 32

#define PHY_FLAG_BROKEN_RESET	(1 << 0) /* soft reset not supported */

#define PHY_DEFAULT_FEATURES	(SUPPORTED_Autoneg | \
				 SUPPORTED_TP | \
				 SUPPORTED_MII)

#define PHY_10BT_FEATURES	(SUPPORTED_10baseT_Half | \
				 SUPPORTED_10baseT_Full)

#define PHY_100BT_FEATURES	(SUPPORTED_100baseT_Half | \
				 SUPPORTED_100baseT_Full)

#define PHY_1000BT_FEATURES	(SUPPORTED_1000baseT_Half | \
				 SUPPORTED_1000baseT_Full)

#define PHY_BASIC_FEATURES	(PHY_10BT_FEATURES | \
				 PHY_100BT_FEATURES | \
				 PHY_DEFAULT_FEATURES)

#define PHY_GBIT_FEATURES	(PHY_BASIC_FEATURES | \
				 PHY_1000BT_FEATURES)

#define PHY_10G_FEATURES	(PHY_GBIT_FEATURES | \
				SUPPORTED_10000baseT_Full)

#ifndef PHY_ANEG_TIMEOUT
#define PHY_ANEG_TIMEOUT	4000
#endif

#define AUTONEG_DISABLE		0x00
#define AUTONEG_ENABLE		0x01

/* The forced speed, 10Mb, 100Mb, gigabit, 2.5Gb, 10GbE. */
#define SPEED_10		10
#define SPEED_100		100
#define SPEED_1000		1000
#define SPEED_2500		2500
#define SPEED_10000		10000

/* Duplex, half or full. */
#define DUPLEX_HALF		0x00
#define DUPLEX_FULL		0x01

/* Indicates what features are supported by the interface. */
#define SUPPORTED_10baseT_Half		(1 << 0)
#define SUPPORTED_10baseT_Full		(1 << 1)
#define SUPPORTED_100baseT_Half		(1 << 2)
#define SUPPORTED_100baseT_Full		(1 << 3)
#define SUPPORTED_1000baseT_Half	(1 << 4)
#define SUPPORTED_1000baseT_Full	(1 << 5)
#define SUPPORTED_Autoneg		    (1 << 6)
#define SUPPORTED_TP			    (1 << 7)
#define SUPPORTED_AUI			    (1 << 8)
#define SUPPORTED_MII			    (1 << 9)
#define SUPPORTED_FIBRE			    (1 << 10)
#define SUPPORTED_BNC			    (1 << 11)
#define SUPPORTED_10000baseT_Full	(1 << 12)
#define SUPPORTED_Pause			    (1 << 13)
#define SUPPORTED_Asym_Pause		(1 << 14)
#define SUPPORTED_2500baseX_Full	(1 << 15)
#define SUPPORTED_Backplane		    (1 << 16)
#define SUPPORTED_1000baseKX_Full	(1 << 17)
#define SUPPORTED_10000baseKX4_Full	(1 << 18)
#define SUPPORTED_10000baseKR_Full	(1 << 19)
#define SUPPORTED_10000baseR_FEC	(1 << 20)
#define SUPPORTED_1000baseX_Half	(1 << 21)
#define SUPPORTED_1000baseX_Full	(1 << 22)

/* Indicates what features are advertised by the interface. */
#define ADVERTISED_10baseT_Half		(1 << 0)
#define ADVERTISED_10baseT_Full		(1 << 1)
#define ADVERTISED_100baseT_Half	(1 << 2)
#define ADVERTISED_100baseT_Full	(1 << 3)
#define ADVERTISED_1000baseT_Half	(1 << 4)
#define ADVERTISED_1000baseT_Full	(1 << 5)
#define ADVERTISED_Autoneg		(1 << 6)
#define ADVERTISED_TP			(1 << 7)
#define ADVERTISED_AUI			(1 << 8)
#define ADVERTISED_MII			(1 << 9)
#define ADVERTISED_FIBRE		(1 << 10)
#define ADVERTISED_BNC			(1 << 11)
#define ADVERTISED_10000baseT_Full	(1 << 12)
#define ADVERTISED_Pause		(1 << 13)
#define ADVERTISED_Asym_Pause		(1 << 14)
#define ADVERTISED_2500baseX_Full	(1 << 15)
#define ADVERTISED_Backplane		(1 << 16)
#define ADVERTISED_1000baseKX_Full	(1 << 17)
#define ADVERTISED_10000baseKX4_Full	(1 << 18)
#define ADVERTISED_10000baseKR_Full	(1 << 19)
#define ADVERTISED_10000baseR_FEC	(1 << 20)
#define ADVERTISED_1000baseX_Half	(1 << 21)
#define ADVERTISED_1000baseX_Full	(1 << 22)



typedef struct mii_device
{
    qe_dev dev;
    int (*read)(struct mii_device *bus, int addr, int reg);
    qe_ret (*write)(struct mii_device *bus, int addr, int reg, qe_u16 val);
    int (*reset)(struct mii_device *bus);
    void *priv;
} mii_dev;

struct phy_device;

typedef struct 
{
    qe_str name;

    qe_u32 uid;
    qe_u32 features;

    qe_ret (*probe)(struct phy_device *dev);

    qe_ret (*config)(struct phy_device *dev);

    qe_ret (*startup)(struct phy_device *dev);

    qe_ret (*shutdown)(struct phy_device *dev);

    int (*readext)(struct phy_device *dev, int addr, int devad, int reg);
    int (*writeext)(struct phy_device *dev, int addr, int devad, int reg, qe_u16 val);

    qe_list list;
} phy_driver;

typedef struct phy_device
{
    mii_dev *bus;
    int speed;
    int duplex;
    int link;

    qe_u32 advertising;
    qe_u32 supported;

    phy_interface_mode interface;
    phy_driver *drv;

    int autoneg;
	int addr;
    int pause;
    int asym_pause;
	qe_u32 phy_id;
	qe_u32 flags;

    void *priv;
} phy_dev;


static inline int phy_read(phy_dev *phydev, int regnum)
{
	mii_dev *bus = phydev->bus;
	return bus->read(bus, phydev->addr, regnum);
}

static inline qe_ret phy_write(phy_dev *phydev, int regnum, qe_u16 val)
{
	mii_dev *bus = phydev->bus;
	return bus->write(bus, phydev->addr, regnum, val);
}

void 
phy_driver_register(phy_driver *drv);

phy_dev *
phy_connect(mii_dev *bus, int addr, phy_interface_mode interface);

qe_ret 
phy_config(phy_dev *phy);


#endif
